package org.bendev.ildaplayer;

import java.text.DateFormatSymbols;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;

import org.bendev.ildaplayer.SolrAdapter.Program;

import android.app.ActionBar;
import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.format.DateFormat;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.widget.Button;
import android.widget.CalendarView;
import android.widget.HorizontalScrollView;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;

public class ProgramListActivity extends Activity {
	static final String
		TAG = "ProgramList",
		PROGRAM = "program",
		DATE_FORMAT = "dd-MM";
	static final String[]
		GENRES = new String[]{ "", "#B3C6FF", "#C6B3FF", "#ECB3FF", "#FFB3EC", "#B3FFEC", "#FFCD38", "#FFDD75", "#FFC6B3", "#B3FFC6", "#C6FFB3", "#ECFFB3" };
	static final int FACTOR = 10000;
	
	Calendar mDate;

	ViewGroup mDaysGroup, mProgramsGroup;
	Button mChannelButton, mDateButton;
	Dialog mChannelDialog, mCalendarDialog, mProgramDetailsDialog;
	ChannelListFragment mChannelsFragment;
	CalendarView mCalendarView;
	View mPrevSelectedView;

	@Override
	protected void onCreate( Bundle savedInstanceState ) {
		super.onCreate( savedInstanceState );
		setContentView( R.layout.activity_program_list );
		
		final Bundle extras = getIntent().getExtras();

		mDaysGroup = (ViewGroup) findViewById( R.id.days );
		mProgramsGroup = (ViewGroup) findViewById( R.id.programs );
		
		mDaysGroup.removeAllViews();
		mProgramsGroup.removeAllViews();
		mDaysGroup.addView( newTextView(""), new LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT ) );
		ViewGroup vg = newLinearLayoutHorizontal();
		mProgramsGroup.addView( vg, new LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT ) );
		for( int i=0; i<24; ++i )
			vg.addView( newTextView( String.format("%02d",i) ), new LayoutParams( 3600000/FACTOR, LayoutParams.WRAP_CONTENT ) );
		
		LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( LayoutParams.MATCH_PARENT, 0, 1 );
		for( int i=0; i<7; ++i ){
			TextView tv = new TextView( this );
			tv.setGravity( Gravity.CENTER_VERTICAL );
			mDaysGroup.addView( tv, lp );
			mProgramsGroup.addView( newLinearLayoutHorizontal(), lp );
		}

		ActionBar actionBar = getActionBar();
		actionBar.setDisplayShowCustomEnabled(true);
		actionBar.setCustomView( R.layout.action_bar_program_list );
		
		mChannelButton = (Button) actionBar.getCustomView().findViewById( R.id.channel_button );
		mChannelButton.setOnClickListener( new View.OnClickListener() {
			@Override
			public void onClick( View v ) {
				mChannelDialog.show();
				mChannelsFragment.setChannels( extras.getStringArrayList( ChannelListActivity.CHANNELS ) );
			}
		} );
		
		mChannelDialog = new Dialog( this );
		mChannelDialog.requestWindowFeature( Window.FEATURE_NO_TITLE );
		mChannelDialog.setContentView( R.layout.program_list_channels );
		mChannelsFragment = (ChannelListFragment) getFragmentManager().findFragmentById( R.id.channels_fragment );
		mChannelsFragment.setOnChannelClickListener( new ChannelListFragment.OnChannelClickListener() {
			@Override
			public void onChannelClick( String channel ) {
				mChannelDialog.dismiss();
				setChannel( channel );
				update( false );
			}
		} );
		
		mDateButton = (Button) actionBar.getCustomView().findViewById( R.id.date_button );
		mDateButton.setOnClickListener( new View.OnClickListener() {
			@Override
			public void onClick( View v ) {
				Calendar now = DateUtils.date( Calendar.getInstance() );
				mCalendarView.setMinDate( DateUtils.add( DateUtils.week( now ), Calendar.WEEK_OF_YEAR, -4 ).getTimeInMillis() );
				mCalendarView.setMaxDate( DateUtils.add( now, Calendar.DATE, 1 ).getTimeInMillis() );
				mCalendarView.setDate( mDate.getTimeInMillis() );
				mCalendarDialog.show();
			}
		} );
		
		mCalendarDialog = new Dialog( this );
		mCalendarDialog.requestWindowFeature( Window.FEATURE_NO_TITLE );
		mCalendarDialog.setContentView( R.layout.program_list_calendar );
		mCalendarView = (CalendarView) mCalendarDialog.findViewById( R.id.calendar_view );
		mCalendarView.setOnDateChangeListener( new CalendarView.OnDateChangeListener() {
			@Override
			public void onSelectedDayChange( CalendarView view, int year, int month, int dayOfMonth ) {
				setDate( year, month, dayOfMonth );
			}
		} );
		
		mProgramDetailsDialog = new Dialog( this );
		mProgramDetailsDialog.setContentView( R.layout.program_details );
		mProgramDetailsDialog.setOnDismissListener( new DialogInterface.OnDismissListener() {
			@Override
			public void onDismiss( DialogInterface dialog ) {
				if( mPrevSelectedView!=null ){
					setViewSelected( mPrevSelectedView, false );
					mPrevSelectedView = null;
				}
			}
		} );
		
		setDate( DateUtils.week( DateUtils.date( Calendar.getInstance() ) ) );
		setChannel( extras.getString( ChannelListActivity.CHANNEL ) );
		update( true );
	}
	
	void setChannel( String channel ){
		mChannelButton.setText( channel );
	}
	
	void setDate( int year, int month, int dayOfMonth ){
		Calendar cal = DateUtils.week( DateUtils.date( year, month, dayOfMonth ) );
		if( mDate!=null && mDate.equals( cal ) )
			return;
		mCalendarDialog.cancel();
		setDate( cal );
		update( false );
	}
	
	void setDate( Calendar cal ){
		mDate = cal;
		mDateButton.setText( String.format( "%s - %s",
			DateFormat.format( DATE_FORMAT, mDate ),
			DateFormat.format( DATE_FORMAT, DateUtils.add( mDate, Calendar.DATE, 6 ) )
		) );
		String[] wd = new DateFormatSymbols(Locale.FRANCE).getWeekdays();
		for( int i=0; i<7; ++i )
			( (TextView) mDaysGroup.getChildAt( i+1 ) ).setText( String.format( "%s %d", wd[((i+1)%7)+1], DateUtils.add( cal, Calendar.DATE, i ).get( Calendar.DATE ) ) );
	}
	
	@SuppressWarnings( "unchecked" )
	void update( final boolean scrollToNow ){
		setPrograms( Collections.EMPTY_LIST );
		mPrevSelectedView = null;
		
		final ProgressDialog pd = ProgressDialog.show( this, "Loading programs", "Please wait...", true, true, new DialogInterface.OnCancelListener() {
			@Override
			public void onCancel( DialogInterface dialog ) {}
		} );
		
		String channel = mChannelButton.getText().toString();
		SolrAdapter.getPrograms( channel, mDate, DateUtils.add( mDate, Calendar.DATE, 7 ), new SolrAdapter.OnProgramsListener() {
			@Override
			public void onPrograms( List<Program> programs ) {
				setPrograms( programs );
				runOnUiThread( new Runnable(){ public void run(){
					pd.dismiss();
					if( !scrollToNow ) return;
					HorizontalScrollView parent = (HorizontalScrollView) mProgramsGroup.getParent();
					Calendar now = Calendar.getInstance();
					int cw = mProgramsGroup.getWidth(), w = parent.getWidth();
					int pos = (int)( (now.getTimeInMillis() - DateUtils.date( now ).getTimeInMillis() )/FACTOR );
					parent.setScrollX( Math.max( 0, Math.min( cw-w, pos-w/2 ) ) );
				} } );
			}
		} );
	}
	
	void setPrograms( final List<Program> programs ){
		for( int i=0; i<7; ++i )
			( (ViewGroup) mProgramsGroup.getChildAt( i+1 ) ).removeAllViews();

		Collections.sort( programs, new Comparator<Program>() {
			@Override
			public int compare( Program lhs, Program rhs ) {
				return lhs.start.compareTo( rhs.start );
			}
		} );
		
		int prevRight = 0;
		for( Program program: programs ){
			if( program.stop.compareTo( mDate )<0 )
				continue;
			prevRight = addProgram( program, prevRight, true );
			if( program.start.get( Calendar.DAY_OF_WEEK ) != program.stop.get( Calendar.DAY_OF_WEEK ) )
				prevRight = addProgram( program, prevRight, false );
		}
	}
	
	int addProgram( final Program program, int prevRight, boolean start ){
		if( start ? program.start.compareTo( mDate )<0 : program.stop.compareTo( DateUtils.add( mDate, Calendar.DATE, 7 ) )>0 )
			return prevRight;
		
		int dow = ( ( start ? program.start : program.stop ).get( Calendar.DAY_OF_WEEK ) - mDate.get( Calendar.DAY_OF_WEEK ) + 7 ) % 7;
		long date = DateUtils.add( mDate, Calendar.DATE, dow ).getTimeInMillis();
		long dateEnd = DateUtils.add( mDate, Calendar.DATE, dow+1 ).getTimeInMillis();
		int left = (int)( ( Math.max( date, program.start.getTimeInMillis() ) - date )/FACTOR );
		int right = (int)( ( Math.min( dateEnd, program.stop.getTimeInMillis() ) - date )/FACTOR );
		if( left >= right )
			return prevRight;

		ViewGroup vg = (ViewGroup) mProgramsGroup.getChildAt( dow+1 );
		View view = View.inflate( this, R.layout.program_list_item, null );
		( (TextView) view.findViewById( R.id.title ) ).setText( program.name );
		String bgColor = GENRES[program.genre];
		if( !bgColor.isEmpty() )
			view.setBackgroundColor( (0x4f<<24) | Integer.parseInt( bgColor.substring( 1 ), 16 ) );
		LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( right - left - 1, LayoutParams.MATCH_PARENT );
		if( left < prevRight )
			prevRight = 0;
		lp.setMargins( 0, 0, 1, 1 );
		if( left > prevRight )
			lp.leftMargin = left - prevRight;
		vg.addView( view, lp );
		view.setOnClickListener( new View.OnClickListener() {
			@Override
			public void onClick( View v ) {
				showProgramDetails( program, v );
			}
		} );
		return right;
	}
	
	void showProgramDetails( final Program program, final View view ){
		if( mPrevSelectedView != null )
			setViewSelected( mPrevSelectedView, false );
		setViewSelected( mPrevSelectedView = view, true );
		mProgramDetailsDialog.setTitle( program.name );
		StringBuilder sb = new StringBuilder();
		sb.append( DateFormat.format( "EEEE dd MMMM kk:mm", program.start ) );
		sb.append( " (" );
		sb.append( android.text.format.DateUtils.formatElapsedTime( (program.stop.getTimeInMillis()-program.start.getTimeInMillis())/1000 ) );
		sb.append( ")" );
		((TextView) mProgramDetailsDialog.findViewById( R.id.date ) ).setText( sb.toString() );
		((TextView) mProgramDetailsDialog.findViewById( R.id.summary ) ).setText( program.description );
		
		if( program.preciseStart==null ){
			final ImageButton ib = (ImageButton) mProgramDetailsDialog.findViewById( R.id.play_button );
			ib.setEnabled( false );
			SolrAdapter.getProgram( program, new SolrAdapter.OnProgramListener() {
				@Override
				public void onProgram( Program p ) {
					ib.setEnabled( true );
					showProgramDetailsPlay( program );
				}
			} );
		}
		else
			showProgramDetailsPlay( program );
		
		mProgramDetailsDialog.show();
	}
	
	void showProgramDetailsPlay( final Program program ){
		mProgramDetailsDialog.findViewById( R.id.play_button ).setOnClickListener( new View.OnClickListener() {
			@Override
			public void onClick( View v ) {
				mProgramDetailsDialog.cancel();
				startActivity( 
					new Intent( ProgramListActivity.this, PlayerActivity.class )
						.putExtra( PROGRAM, program )
				);
			}
		} );
	}
	
	void setViewSelected( View view, boolean selected ){
		Drawable bg = view.getBackground();
		if( !(bg instanceof ColorDrawable) )
			return;
		int color = ((ColorDrawable)bg).getColor();
		view.setBackgroundColor( Color.argb( selected ? 0x7F : 0x4f, Color.red( color ), Color.green( color ), Color.blue( color ) ) );
	}
	
	ViewGroup newLinearLayoutHorizontal(){
		LinearLayout ll = new LinearLayout(this);
		ll.setOrientation( LinearLayout.HORIZONTAL );
		return ll;
	}
	
	TextView newTextView( String text ){
		TextView tv = new TextView(this);
		tv.setText( text );
		return tv;
	}
}